// License Notification
//======================================================
// Copyright (c) 2010 Channel Intelligence Inc.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// ======================================================




using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using CIP4.Common;

namespace CIP4.RulesEngine
{
    [Serializable]
    public abstract class CIValueType
    {
        public static AtomSourceEnum AtomSourceEnumFromString(string value)
        {
            if (string.Compare(value, "function", true) == 0)
                return AtomSourceEnum.function;
            if (string.Compare(value, "literal", true) == 0)
                return AtomSourceEnum.literal;
            if (string.Compare(value, "namedValue", true) == 0)
                return AtomSourceEnum.namedValue;
            if (string.Compare(value, "parameter", true) == 0)
                return AtomSourceEnum.parameter;
            if (string.Compare(value, "variable", true) == 0)
                return AtomSourceEnum.variable;
            throw new ArgumentException(string.Format("{0} is not a valid AtomSourceEnum value", value));
        }

        public static string RuleXmlNS = Globals.cirNS;

        public static CIValueType Initialize(XElement element)
        {
            if (element.Name == XName.Get("ArithmeticExpression", RuleXmlNS))
                return new ArithmeticExpressionType(element);
            if (element.Name == XName.Get("BooleanExpression", RuleXmlNS))
                return new BooleanExpressionType(element);
            if (element.Name == XName.Get("LogicalExpression", RuleXmlNS))
                return new LogicalExpressionType(element);
            if (element.Name == XName.Get("StringExpression", RuleXmlNS))
                return new StringExpressionType(element);
            if (element.Name == XName.Get("IntegerAtom", RuleXmlNS))
                return new IntegerAtomType(element);
            if (element.Name == XName.Get("DecimalAtom", RuleXmlNS))
                return new DecimalAtomType(element);
            if (element.Name == XName.Get("FloatAtom", RuleXmlNS))
                return new FloatAtomType(element);
            if (element.Name == XName.Get("BooleanAtom", RuleXmlNS))
                return new BooleanAtomType(element);
            if (element.Name == XName.Get("StringAtom", RuleXmlNS))
                return new StringAtomType(element);
            if (element.Name == XName.Get("DateTimeAtom", RuleXmlNS))
                return new DateTimeAtomType(element);
            if (element.Name == XName.Get("SetAtom", RuleXmlNS))
                return new SetAtomType(element);
            throw new ArgumentException(string.Format("Cannot initialize a CIValueType from {0}", element));
        }
        
        Dictionary<string, object> m_Parameters;

        public Dictionary<string, object> Parameters
        {
            get 
            {
                if (m_Parameters == null)
                    m_Parameters = new Dictionary<string, object>();
                return m_Parameters; 
            }
        }
        
        public CIValueType Autochthon
        {
            get
            {
                if (Parent == null)
                    return this;
                return Parent.Autochthon;
            }
        }

        private ExpressionType m_Parent;

        public ExpressionType Parent
        {
            get { return m_Parent; }
            set 
            {
                if (m_Parent != value && m_Parent != null && m_Parent.Operands.Contains(this))
                    m_Parent.Operands.Remove(this);
                if (value != null && !value.Operands.Contains(this))
                    value.Operands.Add(this);
                m_Parent = value; 
            }
        }

        public string XmlFor()
        {
            StringWriter swrtr = new StringWriter();
            XmlTextWriter xwrtr = new XmlTextWriter(swrtr);
            xwrtr.Namespaces = true;
            XmlFor(xwrtr, true);
            return swrtr.ToString();
        }

        public abstract void XmlFor(XmlWriter xwrtr, bool writeNamespace);

        public abstract object Evaluate(IDataPacketType data);

        public abstract bool Check(IDataPacketType data);

        public abstract CIValueType Clone();

        /// <summary>
        /// For an explanation of how to use this see the comment on ActionType.ResolveName
        /// </summary>
        /// <param name="qualifiedName"></param>
        public abstract void ResolveName(string qualifiedName);

        public abstract string ToString(ExpressionFormatEnum format);

        public abstract CIP4PrimitiveType UnderlyingType { get; }

        public abstract bool IsLiteral { get; }

        public abstract bool IsNamedValue { get; }
    }
}
